package de.dailab.graphworld.bean;

import de.dailab.graphworld.ontology.ContractNetProtocol;
import de.dailab.graphworld.ontology.Proposal;
import de.dailab.graphworld.ontology.Registration;
import de.dailab.graphworld.ontology.RegistrationRequest;
import de.dailab.graphworld.ontology.Reply;
import de.dailab.graphworld.ontology.ReplyType;
import de.dailab.graphworld.ontology.Task;
import de.dailab.jiactng.agentcore.comm.ICommunicationAddress;
import de.dailab.jiactng.agentcore.comm.message.JiacMessage;
import de.dailab.jiactng.agentcore.knowledge.IFact;
import java.util.Set;

/**
 * Abstract implementation of a manager role in the Contract Net Protocol.
 *
 * @author Kseniya
 */
public abstract class Manager extends ContractNetProtocolMember {

    @Override
    public void execute() {
        super.execute();
        // initiate registration procedure if necessary
        Set<ICommunicationAddress> contractors = memory.readAllOfType(ICommunicationAddress.class);
//        if (contractors.isEmpty()) {
        if (contractors.size() < 3) {
            sendMsgGroup(new RegistrationRequest());
        }
    }

    @Override
    public void consume(JiacMessage msg) {
        IFact payload = msg.getPayload();
        // collect registration replies
        if (payload instanceof Registration) {
            // remember the replied agent
            receiveRegistration(msg.getSender());
            memory.remove(msg);
        } else if (payload instanceof Reply) {
            Reply reply = (Reply) payload;
            ReplyType type = reply.getType();
            Task task = reply.getTask();
            if (ContractNetProtocol.PROPOSE.equals(type)) {
                consumeProposal((Proposal) payload, msg.getSender());
            } else if (ContractNetProtocol.REFUSE.equals(type)) {
                consumeRefusal((Proposal) payload, msg.getSender());
            } else if (ContractNetProtocol.FAILURE.equals(type)) {
                consumeFailure(task);
            } else if (ContractNetProtocol.INFORM.equals(type)) {
                consumeResult(task);
            }
        }
    }

    private void receiveRegistration(ICommunicationAddress respondent) {
        memory.write(respondent);
    }

    /**
     * Handles the proposal from contractor.
     *
     * @param proposal what contractor proposed
     * @param from contractor's address
     */
    protected abstract void consumeProposal(Proposal proposal, ICommunicationAddress from);

    /**
     * Handles the refusal from contractor.
     *
     * @param proposal what contractor proposed instead
     * @param from contractor's address
     */
    protected abstract void consumeRefusal(Proposal proposal, ICommunicationAddress from);

    /**
     * Handles the task's failure.
     *
     * @param task that failed
     */
    protected abstract void consumeFailure(Task task);

    /**
     * Handles the task's success.
     *
     * @param task that succeed
     */
    protected abstract void consumeResult(Task task);
}
